package xyz.qy.implatform.aspect;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import xyz.qy.imclient.annotation.BanSendMsg;
import xyz.qy.implatform.contant.Constant;
import xyz.qy.implatform.contant.RedisKey;
import xyz.qy.implatform.dto.GroupMessageDTO;
import xyz.qy.implatform.entity.Group;
import xyz.qy.implatform.entity.GroupMember;
import xyz.qy.implatform.exception.GlobalException;
import xyz.qy.implatform.service.IGroupMemberService;
import xyz.qy.implatform.service.IGroupService;
import xyz.qy.implatform.session.SessionContext;
import xyz.qy.implatform.session.UserSession;
import xyz.qy.implatform.util.DateTimeUtils;
import xyz.qy.implatform.util.RedisCache;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 执行次数限制切面
 *
 * @author Polaris
 * @since 2024-10-21
 */
@Slf4j
@Aspect
@Order(80)
@Component
public class BanSendMsgAspect {
    @Resource
    private RedisCache redisCache;

    @Resource
    private IGroupService groupService;

    @Resource
    IGroupMemberService groupMemberService;

    @Pointcut("@annotation(xyz.qy.imclient.annotation.BanSendMsg)")
    public void banSendMagAspect() {
    }

    @Around("banSendMagAspect()")
    public Object aspectBefore(ProceedingJoinPoint point) throws Throwable {
        UserSession session = SessionContext.getSession();
        Long userId = session.getUserId();

        // 网站管理员无需校验
        if (userId.equals(Constant.ADMIN_USER_ID)) {
            return point.proceed();
        }

        // 1、判断管理员是否禁止网站聊天功能
        systemMsgCheck();

        // 2、校验用户是否被禁止聊天功能
        userMsgCheck(userId);

        Class<?> clazz = point.getTarget().getClass();
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = clazz.getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
        BanSendMsg banSendMsg = method.getAnnotation(BanSendMsg.class);
        String msgType = banSendMsg.msgType();
        if (StringUtils.isBlank(msgType)) {
            return point.proceed();
        }

        Object[] args = point.getArgs();
        if (args == null || args.length == 0) {
            throw new GlobalException("参数异常");
        }
        Object arg = args[0];
        if (arg instanceof GroupMessageDTO) {
            log.info("群聊消息校验");
            GroupMessageDTO groupMessageDTO = Convert.convert(GroupMessageDTO.class, arg);
            groupMsgCheck(groupMessageDTO.getGroupId());
            groupMemberMsgCheck(groupMessageDTO.getGroupId(), userId);
        }

        return point.proceed();
    }

    private void systemMsgCheck() {
        Boolean exists = redisCache.hasKey(RedisKey.IM_SYSTEM_MSG_SWITCH);
        if (exists) {
            long expire = redisCache.getExpire(RedisKey.IM_SYSTEM_MSG_SWITCH);
            String msg = null;
            if (expire == -1) {
                msg = "网站聊天功能目前无法使用";
            } else {
                msg = "网站聊天功能目前无法使用，请在" + DateTimeUtils.getTimeValueDesc(expire) + "后再尝试";
            }
            throw new GlobalException(msg);
        }
    }

    private void userMsgCheck(Long userId) {
        Boolean exists = redisCache.hasKey(RedisKey.IM_USER_MSG_SWITCH + userId);
        if (exists) {
            long expire = redisCache.getExpire(RedisKey.IM_USER_MSG_SWITCH + userId);
            String msg = null;
            if (expire == -1) {
                msg = "您已被禁止发送聊天信息";
            } else {
                msg = "您已被禁止发送聊天信息，请在" + DateTimeUtils.getTimeValueDesc(expire) + "后再尝试";
            }
            throw new GlobalException(msg);
        }
    }

    private void groupMsgCheck(Long groupId) {
        Boolean exists = redisCache.hasKey(RedisKey.IM_GROUP_MSG_SWITCH + groupId);
        if (exists) {
            long expire = redisCache.getExpire(RedisKey.IM_GROUP_MSG_SWITCH + groupId);
            String msg = null;
            if (expire == -1) {
                msg = "当前群聊已禁止发送消息";
            } else {
                msg = "当前群聊已禁止发送消息，请在" + DateTimeUtils.getTimeValueDesc(expire) + "后再尝试";
            }
            throw new GlobalException(msg);
        }

        Group group = groupService.getById(groupId);
        if (group == null) {
            throw new GlobalException("当前群聊不存在");
        }

        if (!group.getIsBanned()) {
            return;
        }

        // 没有设置失效时间，则被永久禁止
        Date expireTime = group.getBanExpireTime();
        if (expireTime == null) {
            redisCache.setCacheObject(RedisKey.IM_GROUP_MSG_SWITCH + groupId, "YES");
            throw new GlobalException("当前群聊已禁止发送消息");
        }
        Date now = new Date();

        // 当前时间已过失效时间
        if (now.after(expireTime)) {
            group.setIsBanned(false);
            group.setBanMsgType("");
            groupService.updateById(group);
        } else {
            // 计算两个时间之间的差值
            int between = (int)DateUtil.between(now, expireTime, DateUnit.SECOND);
            redisCache.setCacheObject(RedisKey.IM_GROUP_MSG_SWITCH + groupId, "YES", between, TimeUnit.SECONDS);
            throw new GlobalException("当前群聊已禁止发送消息，请在" + DateTimeUtils.getTimeValueDesc(between) + "后再尝试");
        }
    }

    private void groupMemberMsgCheck(Long groupId, Long userId) {
        Boolean exists = redisCache.hasKey(RedisKey.IM_GROUP_MEMBER_MSG_SWITCH + groupId + ":" + userId);
        if (exists) {
            long expire = redisCache.getExpire(RedisKey.IM_GROUP_MEMBER_MSG_SWITCH + groupId + ":" + userId);
            String msg = null;
            if (expire == -1) {
                msg = "您在当前群聊已被禁止发送消息";
            } else {
                msg = "您在当前群聊已被禁止发送消息，请在" + DateTimeUtils.getTimeValueDesc(expire) + "后再尝试";
            }
            throw new GlobalException(msg);
        }

        GroupMember groupMember = groupMemberService.findByGroupAndUserId(groupId, userId);
        if (groupMember == null) {
            throw new GlobalException("您不是当前群聊成员");
        }

        if (!groupMember.getIsBanned()) {
            return;
        }

        // 没有设置失效时间，则被永久禁止
        Date expireTime = groupMember.getBanExpireTime();
        if (expireTime == null) {
            redisCache.setCacheObject(RedisKey.IM_GROUP_MEMBER_MSG_SWITCH + groupId + ":" + userId, "YES");
            throw new GlobalException("您在当前群聊已被禁止发送消息");
        }
        Date now = new Date();

        // 当前时间已过失效时间
        if (now.after(expireTime)) {
            groupMember.setIsBanned(false);
            groupMember.setBanMsgType("");
            groupMemberService.updateById(groupMember);
        } else {
            // 计算两个时间之间的差值
            int between = (int)DateUtil.between(now, expireTime, DateUnit.SECOND);
            redisCache.setCacheObject(RedisKey.IM_GROUP_MEMBER_MSG_SWITCH + groupId + ":" + userId, "YES", between, TimeUnit.SECONDS);
            throw new GlobalException("您在当前群聊已被禁止发送消息，请在" + DateTimeUtils.getTimeValueDesc(between) + "后再尝试");
        }
    }
}
